<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="Hexo Theme Redefine">
    
    <meta name="author" content="xiaoeryu">
    <!-- preconnect -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

    
    <!--- Seo Part-->
    
    <link rel="canonical" href="https://xiaoeeyu.github.io/2022/12/11/26-用户程序编程接口及其实现/"/>
    <meta name="robots" content="index,follow">
    <meta name="googlebot" content="index,follow">
    <meta name="revisit-after" content="1 days">
    
    
    
        
        <meta name="description" content="01.内核与用户程序之间的栈切换问题从内核进入用户程序时，使用的是call far指令，这是一个过程调用指令，是需要使用retf指令返回的。过程调用需要隐式的栈操作，使用栈来保存返回地址，因此当call far指令执行时需要将下一条指令的地址压入当前正在使用的栈中保存，也就是内核的栈中。">
<meta property="og:type" content="article">
<meta property="og:title" content="用户程序编程接口及其实现">
<meta property="og:url" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/index.html">
<meta property="og:site_name" content="xiaoeryu">
<meta property="og:description" content="01.内核与用户程序之间的栈切换问题从内核进入用户程序时，使用的是call far指令，这是一个过程调用指令，是需要使用retf指令返回的。过程调用需要隐式的栈操作，使用栈来保存返回地址，因此当call far指令执行时需要将下一条指令的地址压入当前正在使用的栈中保存，也就是内核的栈中。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/ece9a96ffb6a138049089d2e4501acaa.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/6b36567294d1198d09571ace0663403c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/af5adf72e8ff8e697afd26a16f724fd4.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/045ee1d4090c61889bf9cdc6eb188a8f.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/2b832ac9837b7415d63a77403641ae97.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/ad854eef0591d42fe1ccce5858a97c02.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/cb32bf565275d98327fe23c223c2751c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/f544652bb7f4ed2453d57b5826ea103d.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/13cb4f393d56a743c45f57fc45018557.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/1b52744b5b7594ac73020c7bf1880bde.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/399ef3d5492da8102fdca97626a80bff.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/840e693515f2ec110ffa54d2cf589fc1.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/f92bc1d8d48b0065e1f85321f6fd7f01.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/cffe3bc20c22bb6c0d0838d5f97f1b38.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/d9f76df51c8017be3e97601d9ba12156.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/47b044824e22a668d5aeb2b50cd7b2bb.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/7a4cc3780aa0afd2380c9944eb6f623b.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/61f71545c621852f4eebde07416d2585.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/08bc6810d695962b147e3dc0edc4b404.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/eebc49647b46d4e2b4c9efb4c3d2dbab.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/acbb223d65c87a95abe0c1c6a57a075a.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/68b455214947bd9ce839cd7b7c199545.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/5f0099e490a46b3416c67f91f594fa5c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/ac6aa3c66215e25c2f6d1090953ec547.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/4c3b9f98064b65ba4890b24688071a4b.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/80dc47c15fb9439664aebc9dff90824c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/7975a37ae207e8ef8dba0ae97b1d2ca9.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/image-20221113171015954.png">
<meta property="article:published_time" content="2022-12-11T14:44:00.000Z">
<meta property="article:modified_time" content="2023-10-03T04:59:52.010Z">
<meta property="article:author" content="xiaoeryu">
<meta property="article:tag" content="用户程序编程接口及其实现">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://xiaoeeyu.github.io/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/ece9a96ffb6a138049089d2e4501acaa.png">
    
    
    <!--- Icon Part-->
    <link rel="icon" type="image/png" href="/images/rabete.jpg" sizes="192x192">
    <link rel="apple-touch-icon" sizes="180x180" href="/images/rabete.jpg">
    <meta name="theme-color" content="#A31F34">
    <link rel="shortcut icon" href="/images/rabete.jpg">
    <!--- Page Info-->
    
    <title>
        
            用户程序编程接口及其实现 | xiaoeryu
        
    </title>

    
<link rel="stylesheet" href="/fonts/Chillax/chillax.css">


    <!--- Inject Part-->
    

    
<link rel="stylesheet" href="/css/style.css">


    
        
<link rel="stylesheet" href="/css/build/tailwind.css">

    

    
<link rel="stylesheet" href="/fonts/GeistMono/geist-mono.css">

    
<link rel="stylesheet" href="/fonts/Geist/geist.css">

    <!--- Font Part-->
    
    
    
    
    
    

    <script id="hexo-configurations">
    window.config = {"hostname":"xiaoeeyu.github.io","root":"/","language":"zh-CN","path":"search.xml"};
    window.theme = {"articles":{"style":{"font_size":"16px","line_height":1.5,"image_border_radius":"14px","image_alignment":"center","image_caption":false,"link_icon":true,"delete_mask":false,"title_alignment":"left","headings_top_spacing":{"h1":"3.2rem","h2":"2.4rem","h3":"1.9rem","h4":"1.6rem","h5":"1.4rem","h6":"1.3rem"}},"word_count":{"enable":true,"count":true,"min2read":true},"author_label":{"enable":true,"auto":false,"list":[]},"code_block":{"copy":true,"style":"mac","highlight_theme":{"light":"github","dark":"vs2015"},"font":{"enable":false,"family":null,"url":null}},"toc":{"enable":true,"max_depth":4,"number":false,"expand":true,"init_open":true},"copyright":{"enable":true,"default":"cc_by_nc_sa"},"lazyload":true,"pangu_js":false,"recommendation":{"enable":false,"title":"推荐阅读","limit":3,"mobile_limit":2,"placeholder":"/images/ball-0101.jpg","skip_dirs":[]}},"colors":{"primary":"#A31F34","secondary":null,"default_mode":"light"},"global":{"fonts":{"chinese":{"enable":false,"family":null,"url":null},"english":{"enable":false,"family":null,"url":null},"title":{"enable":false,"family":null,"url":null}},"content_max_width":"1000px","sidebar_width":"210px","hover":{"shadow":true,"scale":false},"scroll_progress":{"bar":false,"percentage":true},"website_counter":{"url":"https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js","enable":true,"site_pv":true,"site_uv":true,"post_pv":true},"single_page":true,"preloader":{"enable":false,"custom_message":null},"open_graph":true,"google_analytics":{"enable":false,"id":null}},"home_banner":{"enable":true,"style":"fixed","image":{"light":"/images/wallhaven-jxl31y.png","dark":"/images/wallhaven-o5762l.png"},"title":"XIAOERYU","subtitle":{"text":["明心见性，拨云见日","Don't wait, to create"],"hitokoto":{"enable":false,"show_author":false,"api":"https://v1.hitokoto.cn"},"typing_speed":100,"backing_speed":80,"starting_delay":500,"backing_delay":1500,"loop":true,"smart_backspace":true},"text_color":{"light":"#fff","dark":"#d1d1b6"},"text_style":{"title_size":"2.8rem","subtitle_size":"1.5rem","line_height":1.2},"custom_font":{"enable":false,"family":null,"url":null},"social_links":{"enable":true,"style":"default","links":{"github":"https://github.com/xiaoeeyu","instagram":null,"zhihu":null,"twitter":null,"email":"xiaoeryu@163.com"},"qrs":{"weixin":null}}},"plugins":{"feed":{"enable":false},"aplayer":{"enable":false,"type":"fixed","audios":[{"name":null,"artist":null,"url":null,"cover":null,"lrc":null}]},"mermaid":{"enable":false,"version":"9.3.0"}},"version":"2.8.2","navbar":{"auto_hide":false,"color":{"left":"#f78736","right":"#367df7","transparency":35},"width":{"home":"1200px","pages":"1000px"},"links":{"Home":{"path":"/","icon":"fa-regular fa-house"},"Archives":{"path":"/archives","icon":"fa-regular fa-archive"}},"search":{"enable":true,"preload":true}},"page_templates":{"friends_column":2,"tags_style":"blur"},"home":{"sidebar":{"enable":true,"position":"left","first_item":"menu","announcement":null,"show_on_mobile":true,"links":null},"article_date_format":"auto","excerpt_length":200,"categories":{"enable":true,"limit":3},"tags":{"enable":true,"limit":3}},"footerStart":"2022/8/17 11:45:14"};
    window.lang_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 个月前","year":"%s 年前"};
    window.data = {"masonry":false};
  </script>
    
    <!--- Fontawesome Part-->
    
<link rel="stylesheet" href="/fontawesome/fontawesome.min.css">

    
<link rel="stylesheet" href="/fontawesome/brands.min.css">

    
<link rel="stylesheet" href="/fontawesome/solid.min.css">

    
<link rel="stylesheet" href="/fontawesome/regular.min.css">

    
    
    
    
<meta name="generator" content="Hexo 6.3.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>



<body>
	<div class="progress-bar-container">
	

	
	<span class="pjax-progress-bar"></span>
	<!--        <span class="swup-progress-icon">-->
	<!--            <i class="fa-solid fa-circle-notch fa-spin"></i>-->
	<!--        </span>-->
	
</div>

<main class="page-container" id="swup">

	

	<div class="main-content-container flex flex-col justify-between min-h-dvh">
		<div class="main-content-header">
			<header class="navbar-container px-6 md:px-12">
    <div class="navbar-content transition-navbar ">
        <div class="left">
            
                <a class="logo-image h-8 w-8 sm:w-10 sm:h-10 mr-3" href="/">
                    <img src="/images/rabete.jpg" class="w-full h-full rounded-sm">
                </a>
            
            <a class="logo-title" href="/">
                
                xiaoeryu
                
            </a>
        </div>

        <div class="right">
            <!-- PC -->
            <div class="desktop">
                <ul class="navbar-list">
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/"
                                        >
                                    <i class="fa-regular fa-house fa-fw"></i>
                                    首页
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/archives"
                                        >
                                    <i class="fa-regular fa-archive fa-fw"></i>
                                    归档
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                    
                        <li class="navbar-item search search-popup-trigger">
                            <i class="fa-solid fa-magnifying-glass"></i>
                        </li>
                    
                </ul>
            </div>
            <!-- Mobile -->
            <div class="mobile">
                
                    <div class="icon-item search search-popup-trigger"><i class="fa-solid fa-magnifying-glass"></i>
                    </div>
                
                <div class="icon-item navbar-bar">
                    <div class="navbar-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- Mobile sheet -->
    <div class="navbar-drawer h-dvh w-full absolute top-0 left-0 bg-background-color flex flex-col justify-between">
        <ul class="drawer-navbar-list flex flex-col px-4 justify-center items-start">
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/"
                        >
                            <span>
                                首页
                            </span>
                            
                                <i class="fa-regular fa-house fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/archives"
                        >
                            <span>
                                归档
                            </span>
                            
                                <i class="fa-regular fa-archive fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            

            
            
        </ul>

        <div class="statistics flex justify-around my-2.5">
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/tags">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">92</div>
        <div class="label text-third-text-color text-sm">标签</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/categories">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">14</div>
        <div class="label text-third-text-color text-sm">分类</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/archives">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">112</div>
        <div class="label text-third-text-color text-sm">文章</div>
    </a>
</div>
    </div>

    <div class="window-mask"></div>

</header>


		</div>

		<div class="main-content-body transition-fade-up">
			

			<div class="main-content">
				<div class="post-page-container flex relative justify-between box-border w-full h-full">
	<div class="article-content-container">

		<div class="article-title relative w-full">
			
			<div class="w-full flex items-center pt-6 justify-start">
				<h1 class="article-title-regular text-second-text-color tracking-tight text-4xl md:text-6xl font-semibold px-2 sm:px-6 md:px-8 py-3">用户程序编程接口及其实现</h1>
			</div>
			
		</div>

		
		<div class="article-header flex flex-row gap-2 items-center px-2 sm:px-6 md:px-8">
			<div class="avatar w-[46px] h-[46px] flex-shrink-0 rounded-medium border border-border-color p-[1px]">
				<img src="/images/rabete.jpg">
			</div>
			<div class="info flex flex-col justify-between">
				<div class="author flex items-center">
					<span class="name text-default-text-color text-lg font-semibold">xiaoeryu</span>
					
					<span class="author-label ml-1.5 text-xs px-2 py-0.5 rounded-small text-third-text-color border border-shadow-color-1">Lv5</span>
					
				</div>
				<div class="meta-info">
					<div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fa-regular fa-pen-fancy"></i>&nbsp;
        <span class="desktop">2022-12-11 22:44</span>
        <span class="mobile">2022-12-11 22:44</span>
        <span class="hover-info">创建</span>
    </span>
    
        <span class="article-date article-meta-item">
            <i class="fa-regular fa-wrench"></i>&nbsp;
            <span class="desktop">2023-10-03 12:59:52</span>
            <span class="mobile">2023-10-03 12:59:52</span>
            <span class="hover-info">更新</span>
        </span>
    

    
        <span class="article-categories article-meta-item">
            <i class="fa-regular fa-folders"></i>&nbsp;
            <ul>
                
                
                    
                        
                        <li>
                            <a href="/categories/X86%E6%B1%87%E7%BC%96%EF%BC%9A%E5%AE%9E%E6%A8%A1%E5%BC%8F%E5%88%B0%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F/">X86汇编：实模式到保护模式</a>&nbsp;
                        </li>
                    
                    
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fa-regular fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/">用户程序编程接口及其实现</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
    
    
        <span class="article-pv article-meta-item">
            <i class="fa-regular fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

				</div>
			</div>
		</div>
		

		


		<div class="article-content markdown-body px-2 sm:px-6 md:px-8 pb-8">
			<h2 id="01-内核与用户程序之间的栈切换问题"><a href="#01-内核与用户程序之间的栈切换问题" class="headerlink" title="01.内核与用户程序之间的栈切换问题"></a>01.内核与用户程序之间的栈切换问题</h2><p>从内核进入用户程序时，使用的是<mark>call far</mark>指令，这是一个过程调用指令，是需要使用<mark>retf</mark>指令返回的。过程调用需要隐式的栈操作，使用栈来保存返回地址，因此当<mark>call far</mark>指令执行时需要将下一条指令的地址压入当前正在使用的栈中保存，也就是内核的栈中。</p>
<span id="more"></span>

<p>用户程序：</p>
<pre><code class="assembly">start:
         mov eax,ds		;此时DS指向用户程序头部段
         mov fs,eax		;但是我们不能失去对DS的追踪，所以使用其他FS段寄存器重新设置DS

         mov ss, [fs:stack_seg]
         mov esp,stack_end

         ;mov eax,[data_seg]
         ;mov ds,eax

         ;用户程序要做的事情（省略）

         retf 
</code></pre>
<p>一旦将栈切换到用户程序自己的栈中，将无法返回内核，因为<mark>retf</mark>指令执行时要从栈中弹出内核的栈状态到<mark>CS</mark>和<mark>ESP</mark>。但是当前使用的时用户程序的栈而非内核的栈，这些地址时保存在内核的栈中的。</p>
<p>修改用户程序，在进入用户程序之后先保存内核栈的<mark>SS和ESP</mark>再使用用户程序自己的栈，在使用<mark>retf</mark>返回内核时再恢复栈为内核的栈地址：</p>
<p>添加用户栈常量：</p>
<pre><code class="assembly">SECTION data vstart=0

         os_ss             dw 0	;用于保存内核栈的状态
         os_esp            dd 0

         message_1         db  0x0d,0x0a,0x0d,0x0a
                           db  '**********User program is runing**********'
                           db  0x0d,0x0a,0

data_end:
</code></pre>
<p><mark>retf</mark>时恢复<mark>SS和ESP</mark></p>
<pre><code class="assembly">start:
         mov eax,ds		;此时DS指向用户程序头部段
         mov fs,eax		;但是我们不能失去对DS的追踪，所以使用其他FS段寄存器重新设置DS

         mov ds,[fs:data_seg] ;切换到用户程序自己的数据段

         mov [os_ss],ss       ;将ss的当前值保存到os_ss和os_esp
         mov [os_esp],esp

         mov ss,[fs:stack_seg] ;将栈切换到用户程序自己的栈
         mov esp,stack_end

         mov ss,[os_ss]       ;恢复内核栈的状态
         mov esp,[os_esp]

         ;用户程序要做的事情（省略）

         retf                                     ;将控制权返回到系统
</code></pre>
<p>因为我们在用户代码中保存了内核的栈状态<mark>SS、ESP</mark>，所以就不用在内核中再重复写代码恢复这个状态了。</p>
<ul>
<li>进入用户程序之前临时保存堆栈指针的指令</li>
<li>回到内核之后切换回内核自己堆栈的指令<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/ece9a96ffb6a138049089d2e4501acaa.png" class=""></li>
</ul>
<p>虚拟机验证：修改是可行的</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/6b36567294d1198d09571ace0663403c.png" class="">
<p><strong>虽然可以这样做，但是需要禁止这样的做法。</strong></p>
<ul>
<li><strong>首先因为用户程序不需要为内核提供服务，比如为内核保存栈状态等等</strong></li>
<li><strong>其次内核必须是稳定的，不能依赖于用户程序否则用户程序一旦出错内核也将崩溃是不行的</strong></li>
</ul>
<h2 id="02-内核中位用户程序提供编程支持"><a href="#02-内核中位用户程序提供编程支持" class="headerlink" title="02. 内核中位用户程序提供编程支持"></a>02. 内核中位用户程序提供编程支持</h2><p>在用户程序中暂时无法访问现存，在进入内核之前创建过一个显存的描述符由内核使用。因此我们知道显存的段选择子，在原则上就可以在用户程序中访问显存显示文本。也可以使用内核中的<mark>put_string</mark>例程来显示字符串。</p>
<p>代码如下：</p>
<ul>
<li>定义的字符串</li>
</ul>
<pre><code class="assembly">SECTION data vstart=0

         os_ss             dw 0	;用于保存内核栈的状态
         os_esp            dd 0

         message_1         db  0x0d,0x0a,0x0d,0x0a
                           db  '**********User program is runing**********'
                           db  0x0d,0x0a,0

data_end:
</code></pre>
<ul>
<li>使用显存的描述符</li>
</ul>
<pre><code class="assembly">start:
         mov eax,ds		;此时DS指向用户程序头部段
         mov fs,eax		;但是我们不能失去对DS的追踪，所以使用其他FS段寄存器重新设置DS

         mov ds,[fs:data_seg] ;切换到用户程序自己的数据段

         mov [os_ss],ss       ;将ss的当前值保存到os_ss和os_esp
         mov [os_esp],esp

         mov ss,[fs:stack_seg] ;将栈切换到用户程序自己的栈
         mov esp,stack_end
        
         mov ebx,message_1
         call 0x28:0		;0x28是内核公共历程段的选择子
         					;0是put_string例程在内核公共历程段内的偏移
         mov ss,[os_ss]     ;恢复内核栈的状态
         mov esp,[os_esp]

         ;用户程序要做的事情（省略）

         retf                                     ;将控制权返回到系统
</code></pre>
<p>虚拟机运行成功：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/af5adf72e8ff8e697afd26a16f724fd4.png" class="">
<p>但是通常用户程序不可能知道内核的<mark>段选择子</mark>和内核中的<mark>例程</mark>，所以上述代码一般不会出现。但是用户程序也可以自己安装一些描述符在<mark>GDT</mark>中，如显存的段描述符，不过一般不能这样做，<mark>GDT</mark>只能给内核使用不然有可能会造成内核的崩溃。</p>
<p>所以处理器有了特权级<mark>DPL</mark>的概念，来限制用户程序的权限。但是内核会给用户程序提供一些例程，供其使用（<em>也可以在一定程度上减少用户程序重复造轮子</em>），也叫用户程序接口（API：Applicatio Programming Interface）。</p>
<h2 id="03-用户程序中的符号地址检索表"><a href="#03-用户程序中的符号地址检索表" class="headerlink" title="03. 用户程序中的符号地址检索表"></a>03. 用户程序中的符号地址检索表</h2><p>本节使用<mark>c13_mbr0.asm</mark>作为引导程序：首先创建一些初始的段描述符、进入保护模式、加载内核、对内和进行设置和重定位、最后将控制权交给内核跳转执行内核程序。</p>
<p>内核发布时需要向程序员发布一个内核编程手册，对于我们这个<mark>c13_core1.asm</mark>内核也有一个编程手册：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/045ee1d4090c61889bf9cdc6eb188a8f.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/2b832ac9837b7415d63a77403641ae97.png" class="">
<p>符号地址检索表位于用户程序头部，当内核加载用户程序时需要对这个表进行处理，会将每一个字符串的名字替换成其在内核中的地址，包括段选择子和段内偏移量。如此一来标号处存储的就是对应例程在内核中的地址。在用户程序头部定义符号地址检索表<mark>SALT(Symbol Address Lookup Table)</mark>。<br>如下：</p>
<pre><code class="assembly">SECTION header vstart=0

         program_length   dd program_end          ;程序总长度#0x00
         
         head_len         dd header_end           ;程序头部的长度#0x04

         stack_seg        dd 0                    ;用于接收堆栈段选择子#0x08
         stack_len        dd 1                    ;程序建议的堆栈大小#0x0c
                                                  ;以4KB为单位
                                                  
         prgentry         dd start                ;程序入口#0x10 
         code_seg         dd section.code.start   ;代码段位置#0x14
         code_len         dd code_end             ;代码段长度#0x18

         data_seg         dd section.data.start   ;数据段位置#0x1c
         data_len         dd data_end             ;数据段长度#0x20
             
;-------------------------------------------------------------------------------
         ;符号地址检索表
         salt_items       dd (header_end-salt)/256 ;#0x24
         
         salt:                                     ;#0x28
         PrintString      db  '@PrintString'
                     times 256-($-PrintString) db 0
                     
         TerminateProgram db  '@TerminateProgram'
                     times 256-($-TerminateProgram) db 0
                     
         ReadDiskData     db  '@ReadDiskData'
                     times 256-($-ReadDiskData) db 0
                 
header_end:   
</code></pre>
<h2 id="04-内核程序中的符号地址检索表"><a href="#04-内核程序中的符号地址检索表" class="headerlink" title="04. 内核程序中的符号地址检索表"></a>04. 内核程序中的符号地址检索表</h2><p>本节主要讲了内核中的符号地址检索表<mark>SALT</mark>的内容，在<mark>c13_core1.asm</mark>中的定义如下：</p>
<pre><code class="assembly">SECTION core_data vstart=0                  ;系统核心的数据段
;-------------------------------------------------------------------------------
         pgdt             dw  0             ;用于设置和修改GDT 
                          dd  0

         ram_alloc        dd  0x00100000    ;下次分配内存时的起始地址

         ;符号地址检索表
         salt:
         salt_1           db  '@PrintString'
                     times 256-($-salt_1) db 0
                          dd  put_string
                          dw  sys_routine_seg_sel

         salt_2           db  '@ReadDiskData'
                     times 256-($-salt_2) db 0
                          dd  read_hard_disk_0
                          dw  sys_routine_seg_sel

         salt_3           db  '@PrintDwordAsHexString'
                     times 256-($-salt_3) db 0
                          dd  put_hex_dword
                          dw  sys_routine_seg_sel

         salt_4           db  '@TerminateProgram'
                     times 256-($-salt_4) db 0
                          dd  return_point
                          dw  core_code_seg_sel

         salt_item_len   equ $-salt_4
         salt_items      equ ($-salt)/salt_item_len
</code></pre>
<h2 id="05-串比较指令CMPS"><a href="#05-串比较指令CMPS" class="headerlink" title="05. 串比较指令CMPS"></a>05. 串比较指令CMPS</h2><p>内核启动流程：</p>
<ul>
<li>从主引导程序进入内核</li>
<li>显示一些文本信息、显示处理器品牌信息</li>
<li>调用<mark>load_relocate_program</mark>加载和重定位用户程序</li>
<li>显示文本信息</li>
<li>调转执行用户程序</li>
</ul>
<p>其中<mark>load_relocate_program</mark>中添加了对符号地址检索表的处理：</p>
<ul>
<li>读硬盘扇区，将用户程序读入内存，为用户程序的每个段创建描述符；</li>
<li>处理符号地址检索表，即将符号出的字符串替换成其对应例程在内存中的地址，替换成例程在内存中的<mark>段选择子</mark>和<mark>段内偏移量</mark>。如何知道每个字符串所代表的例程在内存中的地址呢？<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/ad854eef0591d42fe1ccce5858a97c02.png" class="">
将用户程序中的符号取出，依次和内核中的符号地址检索表中的内容进行比较，相同的话就是用内核中对应的后六个字节的<mark>段选择子</mark>和<mark>段内偏移量</mark>覆盖用户程序原先的符号，覆盖之后用户程序中存放的就是对应例程的<mark>段选择子</mark>和<mark>段内偏移量</mark>。</li>
<li>处理完<mark>SALT</mark>之后返回</li>
</ul>
<p>其中，使用字符串比较指令<mark>cmpsb、cmpsw、cmpsd、cmpsq</mark>进行字符串比较：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/cb32bf565275d98327fe23c223c2751c.png" class="">


<h2 id="06-串比较的方向和重复前缀"><a href="#06-串比较的方向和重复前缀" class="headerlink" title="06. 串比较的方向和重复前缀"></a>06. 串比较的方向和重复前缀</h2><p><mark>CMPS</mark>指令只会执行一次，重复比较需要使用指令重复前缀<mark>rep</mark>。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/f544652bb7f4ed2453d57b5826ea103d.png" class="">

<p><mark>rep</mark>重复前缀：指令每执行一次，<mark>CX/ECX/RCX</mark>值减1。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/13cb4f393d56a743c45f57fc45018557.png" class="">

<p>如果总字节数除不尽的话，应该使用<mark>cmpsb</mark>，而不是<mark>cmpsw</mark>指令，<mark>CX、ECX、RCX</mark>设置的总字节数是字符串的长度，所以两个字符串长度要相等。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/1b52744b5b7594ac73020c7bf1880bde.png" class="">

<p>重复前缀<mark>rep</mark>指令不会在比较字符串时做出判断，这个问题使用如下方法解决：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/399ef3d5492da8102fdca97626a80bff.png" class="">

<p>例如指令，<mark>repe cmpsw</mark>，执行过程是：以字节为单位进行字符串比较，若相等则设置零标志位<mark>ZF = 1</mark>，也将<mark>CX/ECX/RCX</mark>减1，若<mark>CX/ECX/RCX</mark>不为零且<mark>ZF = 1</mark>，表示字符串相等继续比较，若在<mark>C<br>X/ECX/RCX</mark>不为零但是<mark>ZF = 0</mark>则表示当前字符串不相等，比较终止。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/840e693515f2ec110ffa54d2cf589fc1.png" class="">

<p>字符串比较的完整过程：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/f92bc1d8d48b0065e1f85321f6fd7f01.png" class="">

<h2 id="07-使用外循环依次取得用户SALT表中的每个条目"><a href="#07-使用外循环依次取得用户SALT表中的每个条目" class="headerlink" title="07. 使用外循环依次取得用户SALT表中的每个条目"></a>07. 使用外循环依次取得用户SALT表中的每个条目</h2><p>接05节：<br>在<mark>load_relocate_program</mark>中，添加了符号地址检索表<mark>SALT</mark>的重定位过程：</p>
<pre><code>SECTION core_code vstart=0
;-------------------------------------------------------------------------------
load_relocate_program:                      ;加载并重定位用户程序
                                            ;输入：ESI=起始逻辑扇区号
                                            ;返回：AX=指向用户程序头部的选择子
                                            
        ...
        ...
        ...
        

         ;重定位SALT
         mov eax,[edi+0x04]
         mov es,eax                         ;es -&gt; 用户程序头部 
         mov eax,core_data_seg_sel
         mov ds,eax
      
         cld

         mov ecx,[es:0x24]                  ;用户程序的SALT条目数
         mov edi,0x28                       ;用户程序内的SALT位于头部内0x2c处
  .b2: 
         push ecx
         push edi
      
         mov ecx,salt_items
         mov esi,salt
  .b3:
         push edi
         push esi
         push ecx

         mov ecx,64                         ;检索表中，每条目的比较次数 
         repe cmpsd                         ;每次比较4字节 
         jnz .b4
         mov eax,[esi]                      ;若匹配，esi恰好指向其后的地址数据
         mov [es:edi-256],eax               ;将字符串改写成偏移地址 
         mov ax,[esi+4]
         mov [es:edi-252],ax                ;以及段选择子 
  .b4:
      
         pop ecx
         pop esi
         add esi,salt_item_len
         pop edi                            ;从头比较 
         loop .b3
      
         pop edi
         add edi,256
         pop ecx
         loop .b2

         mov ax,[es:0x04]

         pop es                             ;恢复到调用此过程前的es段 
         pop ds                             ;恢复到调用此过程前的ds段
      
         pop edi
         pop esi
         pop edx
         pop ecx
         pop ebx
      
         ret
</code></pre>
<p>其中：在用户程序中，偏移<mark>为4</mark>的地方之前是用户程序头部段的长度，现在被修改为用户程序头部段的选择子。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/cffe3bc20c22bb6c0d0838d5f97f1b38.png" class="">

<p>其中比较过程使用循环进行，外循环遍历用户程序、内存换遍历内核程序：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/d9f76df51c8017be3e97601d9ba12156.png" class="">

<p>外循环：每执行一次都会使得<mark>EDI</mark>指向代表下一个例程名称字符串的首地址。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/47b044824e22a668d5aeb2b50cd7b2bb.png" class="">


<h2 id="08-使用内循环依次取得内核SALT表中的每个条目并进行比较"><a href="#08-使用内循环依次取得内核SALT表中的每个条目并进行比较" class="headerlink" title="08. 使用内循环依次取得内核SALT表中的每个条目并进行比较"></a>08. 使用内循环依次取得内核SALT表中的每个条目并进行比较</h2><p>在上一节中：<mark>EDI</mark>增量为256字节、<mark>ESI</mark>增量为262字节。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/7a4cc3780aa0afd2380c9944eb6f623b.png" class="">

<p>内循环：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/61f71545c621852f4eebde07416d2585.png" class="">

<p>其中，字符串比较：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/08bc6810d695962b147e3dc0edc4b404.png" class="">

<p>执行比较之前：</p>
<ul>
<li>现在段寄存器<mark>ES</mark>指向用户程序数据段；</li>
<li><mark>EDI</mark>指向用户程序符号地址检索表的某个条目；</li>
<li>段寄存器<mark>DS</mark>指向内核数据段；</li>
<li><mark>ESI</mark>指向内核符号地址检索表的某个条目；</li>
</ul>
<p>在检索表中，每个字符串的长度是<mark>256个字节 = 64个双字</mark>；<br>如果两个字符串相同，比较操作要进行64次，结束后零标志位ZF = 1;<br>如果两个字符串不同，比较操作中止，此时零标志位ZF = 0。</p>
<p>如果比较结束之后<mark>ZF = 1</mark>，表示字符串相同，执行重定位操作：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/eebc49647b46d4e2b4c9efb4c3d2dbab.png" class="">

<p>具体过程看下面代码：</p>
<pre><code class="assembly">         mov ecx,64                         ;检索表中，每条目的比较次数 
         repe cmpsd                         ;每次比较4字节 
         jnz .b4
         mov eax,[esi]                      ;若匹配，esi恰好指向其后的地址数据
         mov [es:edi-256],eax               ;将字符串改写成偏移地址 
         mov ax,[esi+4]
         mov [es:edi-252],ax                ;以及段选择子 
</code></pre>
<h2 id="09-用户程序中使用内核编程接口读硬盘和显示文本"><a href="#09-用户程序中使用内核编程接口读硬盘和显示文本" class="headerlink" title="09. 用户程序中使用内核编程接口读硬盘和显示文本"></a>09. 用户程序中使用内核编程接口读硬盘和显示文本</h2><p>其中在内核跳转执行用户程序时，使用<mark>jmp far [0x08]</mark>指令，不需要在栈中压入返回地址；之前使用<mark>call</mark>指令需要在栈中压入返回地址，所以有栈的切换问题。</p>
<p>进入用户程序执行，使用内核例程。</p>
<pre><code class="assembly">SECTION code vstart=0

start:
    mov eax,ds
    mov fs,eax
    
    mov ss,[fs:stack_seg]      			;ss指向用户程序自己的栈段
    mov esp,stack_end
    
    mov ds,[fs:data_seg]				;ds指向用户程序自己的数据段
    
    mov ebx,message_1         			;ebx指向偏移地址
    call far [fs:PrintString]			;调用内核put_string例程
    
    mov eax,100                 		;逻辑扇区号100
    mov ebx,buffer              		;缓冲区偏移地址
    call far [fs:ReadDiskData]  		;段间调用
    
    mov ebx,message_2
    call far [fs:PrintString]
    
    mov ebx,buffer
    call far [fs:PrintString]           ;too.
    
    jmp far [fs:TerminateProgram]       ;将控制权返回到系统

code_end:
</code></pre>
<h2 id="10-虚拟机验证程序执行"><a href="#10-虚拟机验证程序执行" class="headerlink" title="10. 虚拟机验证程序执行"></a>10. 虚拟机验证程序执行</h2><p>先用Vhd Writer讲文件写入要读取的<mark>100号扇区</mark><br>再使用<mark>VirtualBox</mark>虚拟机测试代码</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/acbb223d65c87a95abe0c1c6a57a075a.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/68b455214947bd9ce839cd7b7c199545.png" class="">


<h2 id="11-以16进制形式显示一个双字以及PUSHAD、POPAD和XLAT指令的使用"><a href="#11-以16进制形式显示一个双字以及PUSHAD、POPAD和XLAT指令的使用" class="headerlink" title="11. 以16进制形式显示一个双字以及PUSHAD、POPAD和XLAT指令的使用"></a>11. 以16进制形式显示一个双字以及PUSHAD、POPAD和XLAT指令的使用</h2><p>在内核中实现了<mark>put_hex_dword</mark>例程：</p>
<pre><code class="assembly">    ;汇编语言程序是极难一次成功，而且调试非常困难。这个例程可以提供帮助
put_hex_dword:					;在当前光标处以十六进制形式显示
                                ;一个双字并推进光标
                                ;输入：EDX=要转换并显示的数字
                                ;输出：无
    pushad
    push ds
    
    mov ax,core_data_seg_sel    ;切换到核心数据段
    mov ds,ax
    
    mov ebx,bin_hex             ;指向核心数据段内的转换表
    mov ecx,8
.xlt:
    rol edx,4
    mov eax,edx
    and eax,0x0000000f
    xlat
    
    push ecx
    mov cl,al
    call put_char
    pop ecx
    
    loop .xlt
    
    pop ds
    popad
    
    retf
</code></pre>
<p>使用上述例程显示一个双字的16进制形式。</p>
<p>在内核数据段中定义了一个字符串：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/5f0099e490a46b3416c67f91f594fa5c.png" class="">
<p>每个字符在字符串中的偏移正好可以代表其作为16进制的数字字符。</p>
<p>将32位二进制数分成8个4位，将每个4位二进制数据转化为16进制，再用值作为偏移去取出对应的字符显示出来即可。</p>
<p>其中<mark>pushad</mark>：每次先将<mark>ESP减4</mark>，<mark>ESP</mark>是先保存再压入。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/ac6aa3c66215e25c2f6d1090953ec547.png" class="">
<p>对应的<mark>popad</mark>指令：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/4c3b9f98064b65ba4890b24688071a4b.png" class="">
<p>其中<mark>xalt</mark>指令：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/80dc47c15fb9439664aebc9dff90824c.png" class="">
<p>运行过程：将<mark>EDX</mark>循环左移4位，再备份到<mark>EAX</mark>中，<mark>EAX</mark>除了低四位外全部置零，就可以获取<mark>AL</mark>的值了。</p>
<p>课后作业：<br>使用<mark>put_hex_dword</mark>在屏幕上输出一串数字：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/7975a37ae207e8ef8dba0ae97b1d2ca9.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/image-20221113171015954.png" class="" title="image-20221113171015954">

		</div>

		
		<div class="post-copyright-info w-full my-8 px-2 sm:px-6 md:px-8">
			<div class="article-copyright-info-container">
    <ul>
        <li><strong>标题:</strong> 用户程序编程接口及其实现</li>
        <li><strong>作者:</strong> xiaoeryu</li>
        <li><strong>创建于
                :</strong> 2022-12-11 22:44:00</li>
        
            <li>
                <strong>更新于
                    :</strong> 2023-10-03 12:59:52
            </li>
        
        <li>
            <strong>链接:</strong> https://github.com/xiaoeryu/2022/12/11/26-用户程序编程接口及其实现/
        </li>
        <li>
            <strong>
                版权声明:
            </strong>
            

            
                本文章采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0">CC BY-NC-SA 4.0</a> 进行许可。
            
        </li>
    </ul>
</div>

		</div>
		

		
		<ul class="post-tags-box text-lg mt-1.5 flex-wrap justify-center flex md:hidden">
			
			<li class="tag-item mx-0.5">
				<a href="/tags/%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/">#用户程序编程接口及其实现</a>&nbsp;
			</li>
			
		</ul>
		

		

		
		<div class="article-nav my-8 flex justify-between items-center px-2 sm:px-6 md:px-8">
			
			<div class="article-prev border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="prev" rel="prev" href="/2022/12/11/27-%E4%BB%BB%E5%8A%A1%E5%92%8C%E4%BB%BB%E5%8A%A1%E7%9A%84%E5%88%9B%E5%BB%BA/">
					<span class="left arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-left"></i>
					</span>
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">任务和任务的创建</span>
						<span class="post-nav-item">上一篇</span>
					</span>
				</a>
			</div>
			
			
			<div class="article-next border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="next" rel="next" href="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/">
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">保护模式程序的动态加载和执行</span>
						<span class="post-nav-item">下一篇</span>
					</span>
					<span class="right arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-right"></i>
					</span>
				</a>
			</div>
			
		</div>
		


		
		<div class="comment-container px-2 sm:px-6 md:px-8 pb-8">
			<div class="comments-container mt-10 w-full ">
    <div id="comment-anchor" class="w-full h-2.5"></div>
    <div class="comment-area-title w-full my-1.5 md:my-2.5 text-xl md:text-3xl font-bold">
        评论
    </div>
    

        
            


        
    
</div>

		</div>
		
	</div>

	
	<div class="toc-content-container">
		<div class="post-toc-wrap">
	<div class="post-toc">
		<div class="toc-title">目录</div>
		<div class="page-title">用户程序编程接口及其实现</div>
		<ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#01-%E5%86%85%E6%A0%B8%E4%B8%8E%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E4%B9%8B%E9%97%B4%E7%9A%84%E6%A0%88%E5%88%87%E6%8D%A2%E9%97%AE%E9%A2%98"><span class="nav-text">01.内核与用户程序之间的栈切换问题</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#02-%E5%86%85%E6%A0%B8%E4%B8%AD%E4%BD%8D%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E6%8F%90%E4%BE%9B%E7%BC%96%E7%A8%8B%E6%94%AF%E6%8C%81"><span class="nav-text">02. 内核中位用户程序提供编程支持</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#03-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E4%B8%AD%E7%9A%84%E7%AC%A6%E5%8F%B7%E5%9C%B0%E5%9D%80%E6%A3%80%E7%B4%A2%E8%A1%A8"><span class="nav-text">03. 用户程序中的符号地址检索表</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#04-%E5%86%85%E6%A0%B8%E7%A8%8B%E5%BA%8F%E4%B8%AD%E7%9A%84%E7%AC%A6%E5%8F%B7%E5%9C%B0%E5%9D%80%E6%A3%80%E7%B4%A2%E8%A1%A8"><span class="nav-text">04. 内核程序中的符号地址检索表</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#05-%E4%B8%B2%E6%AF%94%E8%BE%83%E6%8C%87%E4%BB%A4CMPS"><span class="nav-text">05. 串比较指令CMPS</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#06-%E4%B8%B2%E6%AF%94%E8%BE%83%E7%9A%84%E6%96%B9%E5%90%91%E5%92%8C%E9%87%8D%E5%A4%8D%E5%89%8D%E7%BC%80"><span class="nav-text">06. 串比较的方向和重复前缀</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#07-%E4%BD%BF%E7%94%A8%E5%A4%96%E5%BE%AA%E7%8E%AF%E4%BE%9D%E6%AC%A1%E5%8F%96%E5%BE%97%E7%94%A8%E6%88%B7SALT%E8%A1%A8%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%AA%E6%9D%A1%E7%9B%AE"><span class="nav-text">07. 使用外循环依次取得用户SALT表中的每个条目</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#08-%E4%BD%BF%E7%94%A8%E5%86%85%E5%BE%AA%E7%8E%AF%E4%BE%9D%E6%AC%A1%E5%8F%96%E5%BE%97%E5%86%85%E6%A0%B8SALT%E8%A1%A8%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%AA%E6%9D%A1%E7%9B%AE%E5%B9%B6%E8%BF%9B%E8%A1%8C%E6%AF%94%E8%BE%83"><span class="nav-text">08. 使用内循环依次取得内核SALT表中的每个条目并进行比较</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#09-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E4%B8%AD%E4%BD%BF%E7%94%A8%E5%86%85%E6%A0%B8%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E8%AF%BB%E7%A1%AC%E7%9B%98%E5%92%8C%E6%98%BE%E7%A4%BA%E6%96%87%E6%9C%AC"><span class="nav-text">09. 用户程序中使用内核编程接口读硬盘和显示文本</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#10-%E8%99%9A%E6%8B%9F%E6%9C%BA%E9%AA%8C%E8%AF%81%E7%A8%8B%E5%BA%8F%E6%89%A7%E8%A1%8C"><span class="nav-text">10. 虚拟机验证程序执行</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#11-%E4%BB%A516%E8%BF%9B%E5%88%B6%E5%BD%A2%E5%BC%8F%E6%98%BE%E7%A4%BA%E4%B8%80%E4%B8%AA%E5%8F%8C%E5%AD%97%E4%BB%A5%E5%8F%8APUSHAD%E3%80%81POPAD%E5%92%8CXLAT%E6%8C%87%E4%BB%A4%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="nav-text">11. 以16进制形式显示一个双字以及PUSHAD、POPAD和XLAT指令的使用</span></a></li></ol>

	</div>
</div>
	</div>
	
</div>
			</div>

			
		</div>

		<div class="main-content-footer">
			<footer class="footer mt-5 py-5 h-auto text-base text-third-text-color relative border-t-2 border-t-border-color">
    <div class="info-container py-3 text-center">
        
        <div class="text-center">
            &copy;
            
              <span>2022</span>
              -
            
            2025&nbsp;&nbsp;<i class="fa-solid fa-heart fa-beat" style="--fa-animation-duration: 0.5s; color: #f54545"></i>&nbsp;&nbsp;<a href="/">xiaoeryu</a>
            
                
                <p class="post-count space-x-0.5">
                    <span>
                        共撰写了 112 篇文章
                    </span>
                    
                </p>
            
        </div>
        
            <script data-swup-reload-script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="relative text-center lg:absolute lg:right-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-right">
                
                    <span id="busuanzi_container_site_uv" class="lg:!block">
                        <span class="text-sm">访问人数</span>
                        <span id="busuanzi_value_site_uv"></span>
                    </span>
                
                
                    <span id="busuanzi_container_site_pv" class="lg:!block">
                        <span class="text-sm">总访问量</span>
                        <span id="busuanzi_value_site_pv"></span>
                    </span>
                
            </div>
        
        <div class="relative text-center lg:absolute lg:left-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-left">
            <span class="lg:block text-sm">由 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="relative top-[2px] inline-block align-baseline" version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1rem" height="1rem" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><path fill="#0E83CD" d="M256.4,25.8l-200,115.5L56,371.5l199.6,114.7l200-115.5l0.4-230.2L256.4,25.8z M349,354.6l-18.4,10.7l-18.6-11V275H200v79.6l-18.4,10.7l-18.6-11v-197l18.5-10.6l18.5,10.8V237h112v-79.6l18.5-10.6l18.5,10.8V354.6z"/></svg><a target="_blank" class="text-base" href="https://hexo.io">Hexo</a> 驱动</span>
            <span class="text-sm lg:block">主题&nbsp;<a class="text-base" target="_blank" href="https://github.com/EvanNotFound/hexo-theme-redefine">Redefine v2.8.2</a></span>
        </div>
        
        
            <div>
                博客已运行 <span class="odometer" id="runtime_days" ></span> 天 <span class="odometer" id="runtime_hours"></span> 小时 <span class="odometer" id="runtime_minutes"></span> 分钟 <span class="odometer" id="runtime_seconds"></span> 秒
            </div>
        
        
            <script data-swup-reload-script>
                try {
                    function odometer_init() {
                    const elements = document.querySelectorAll('.odometer');
                    elements.forEach(el => {
                        new Odometer({
                            el,
                            format: '( ddd).dd',
                            duration: 200
                        });
                    });
                    }
                    odometer_init();
                } catch (error) {}
            </script>
        
        
        
    </div>  
</footer>
		</div>
	</div>

	
	<div class="post-tools">
		<div class="post-tools-container">
	<ul class="article-tools-list">
		<!-- TOC aside toggle -->
		
		<li class="right-bottom-tools page-aside-toggle">
			<i class="fa-regular fa-outdent"></i>
		</li>
		

		<!-- go comment -->
		
		<li class="go-comment">
			<i class="fa-regular fa-comments"></i>
		</li>
		
	</ul>
</div>
	</div>
	

	<div class="right-side-tools-container">
		<div class="side-tools-container">
	<ul class="hidden-tools-list">
		<li class="right-bottom-tools tool-font-adjust-plus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-plus"></i>
		</li>

		<li class="right-bottom-tools tool-font-adjust-minus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-minus"></i>
		</li>

		<li class="right-bottom-tools tool-dark-light-toggle flex justify-center items-center">
			<i class="fa-regular fa-moon"></i>
		</li>

		<!-- rss -->
		

		

		<li class="right-bottom-tools tool-scroll-to-bottom flex justify-center items-center">
			<i class="fa-regular fa-arrow-down"></i>
		</li>
	</ul>

	<ul class="visible-tools-list">
		<li class="right-bottom-tools toggle-tools-list flex justify-center items-center">
			<i class="fa-regular fa-cog fa-spin"></i>
		</li>
		
		<li class="right-bottom-tools tool-scroll-to-top flex justify-center items-center">
			<i class="arrow-up fas fa-arrow-up"></i>
			<span class="percent"></span>
		</li>
		
		
	</ul>
</div>
	</div>

	<div class="image-viewer-container">
	<img src="">
</div>

	
	<div class="search-pop-overlay">
	<div class="popup search-popup">
		<div class="search-header">
			<span class="search-input-field-pre">
				<i class="fa-solid fa-keyboard"></i>
			</span>
			<div class="search-input-container">
				<input autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="站内搜索您需要的内容..." spellcheck="false" type="search" class="search-input">
			</div>
			<span class="popup-btn-close">
				<i class="fa-solid fa-times"></i>
			</span>
		</div>
		<div id="search-result">
			<div id="no-result">
				<i class="fa-solid fa-spinner fa-spin-pulse fa-5x fa-fw"></i>
			</div>
		</div>
	</div>
</div>
	

</main>



<script src="/js/build/libs/Swup.min.js"></script>

<script src="/js/build/libs/SwupSlideTheme.min.js"></script>

<script src="/js/build/libs/SwupScriptsPlugin.min.js"></script>

<script src="/js/build/libs/SwupProgressPlugin.min.js"></script>

<script src="/js/build/libs/SwupScrollPlugin.min.js"></script>

<script src="/js/build/libs/SwupPreloadPlugin.min.js"></script>

<script>
    const swup = new Swup({
        plugins: [
            new SwupScriptsPlugin({
                optin: true,
            }),
            new SwupProgressPlugin(),
            new SwupScrollPlugin({
                offset: 80,
            }),
            new SwupSlideTheme({
                mainElement: ".main-content-body",
            }),
            new SwupPreloadPlugin(),
        ],
        containers: ["#swup"],
    });
</script>




	
<script src="/js/build/tools/imageViewer.js" type="module"></script>

<script src="/js/build/utils.js" type="module"></script>

<script src="/js/build/main.js" type="module"></script>

<script src="/js/build/layouts/navbarShrink.js" type="module"></script>

<script src="/js/build/tools/scrollTopBottom.js" type="module"></script>

<script src="/js/build/tools/lightDarkSwitch.js" type="module"></script>

<script src="/js/build/layouts/categoryList.js" type="module"></script>



    
<script src="/js/build/tools/localSearch.js" type="module"></script>




    
<script src="/js/build/tools/codeBlock.js" type="module"></script>




    
<script src="/js/build/layouts/lazyload.js" type="module"></script>




    
<script src="/js/build/tools/runtime.js"></script>

    
<script src="/js/build/libs/odometer.min.js"></script>

    
<link rel="stylesheet" href="/assets/odometer-theme-minimal.css">




  
<script src="/js/build/libs/Typed.min.js"></script>

  
<script src="/js/build/plugins/typed.js" type="module"></script>








    
<script src="/js/build/libs/anime.min.js"></script>





    
<script src="/js/build/tools/tocToggle.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/layouts/toc.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/plugins/tabs.js" type="module" data-swup-reload-script=""></script>




<script src="/js/build/libs/moment-with-locales.min.js" data-swup-reload-script=""></script>


<script src="/js/build/layouts/essays.js" type="module" data-swup-reload-script=""></script>





	
</body>

</html>